package com.tqz.rc.common.util;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * <p>根据spring上下文获取容器中的bean。
 *
 * <p>该类实现于 {@link ApplicationContextInitializer} 接口，
 * 这个接口的主要作用是在 {@link ConfigurableApplicationContext} 类型的上下文做刷新之前，
 * 允许我们对 {@link ConfigurableApplicationContext} 的实例做进一步的设置。也就是容器刷新之前被调用的。
 *
 * <p>需要注意的是，在Spring-Boot-Web环境下使用 {@link ApplicationContextInitializer} 接口的时候，有两种使用方式：
 *      1.需要在resources文件夹下面创建 `META-INF/spring.factories` 文件，去实现自动装配的原理，否则我们实现这个接口的类会加载不到。
 *      2.通过启动类去注册我们实现了该接口的类，
 *      <pre>
 *          SpringApplication springApplication = new SpringApplication(TqzRcServerApplication.class);
 *         springApplication.addInitializers(new ApplicationUtil());
 *         springApplication.run(args);
 *      </pre>
 *
 * @author tianqingzhao
 * @since 2021/9/1 14:58
 * @see BeanFactory
 * @see ApplicationContext
 * @see ConfigurableApplicationContext
 */
public class ApplicationContextUtil implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    private static ApplicationContext applicationContext;

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ApplicationContextUtil.applicationContext = applicationContext;
    }

    public static <T> T getBean(Class<T> requiredType) {
        assertApplicationContext();
        return applicationContext.getBean(requiredType);
    }

    public static <T> T getBean(String beanName, Class<T> requiredType) {
        return applicationContext.getBean(beanName, requiredType);
    }

    private static void assertApplicationContext() {
        if (ApplicationContextUtil.applicationContext == null) {
            throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了SpringContextHolder!");
        }
    }
}
